#include "FastLED.h"
#include <ESP8266WiFi.h>      //To USE pattern STA & AP
#include <ESP8266WiFiMulti.h> //To connect multipie WiFi
#include <ESP8266WebServer.h>
#include <DNSServer.h>//change
#include <FS.h>

// 落日颜色：a62f09
#define NUM_LEDS 10
#define DATA_PIN 16
#define BUTTON 0 // FALSH 按键
#define BUTTON_INDEX 5 // FALSH 按键

#define LED_TYPE WS2812
#define COLOR_ORDER GRB

uint8_t brightness = 60;

uint8_t pattern = 2;
uint8_t RED = 166;
uint8_t GREEN = 47;
uint8_t BLUE = 9;
uint8_t i;
bool button;
bool button_index;
uint8_t count = 0;

bool debug = 1; // 调试按钮
bool TURN=0;
bool INDEX=1;

String filetostorepattern = "./ftsp.txt";    // 被读取的文件位置和名称 file to store pattern
String filetostorebrightness = "./ftsb.txt"; // 被读取的文件位置和名称 file to store brightness
String filetostoreindex = "./ftsi.txt"; // 被读取的文件位置和名称 file to store brightness

const char *AP_NAME = "小夜灯";      // wifi名字

const byte DNS_PORT = 53;       // DNS端口号
IPAddress apIP(192, 168, 4, 1); // esp8266-AP-IP地址
DNSServer dnsServer;            // 创建dnsServer实例
CRGB leds[NUM_LEDS];            // 建立WS2812B实体对象
// ESP8266WiFiMulti wifiMulti;          // 建立ESP8266WiFiMulti对象
ESP8266WebServer esp8266_server(80); // 建立ESP8266WebServer对象，该对象用于响应HTTP请求。监听端口（80）

void setup()
{
  // Set Serial
  if (debug)
  {
    Serial.begin(9600);
    Serial.println("");
  }
  // Set WS2812
  FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(brightness);

  // Set Web-AP

  WiFi.hostname("Smart-ESP8266"); // 设置ESP8266设备名
                                  ////wifiMulti.addAP("zhouliangan44", "wxg13948532823"); // 将需要连接的一系列WiFi ID和密码输入这里

  // while (wifiMulti.run() != WL_CONNECTED)
  // { // 尝试进行wifi连接。
  //   delay(1000);
  //   if (debug)
  //     Serial.print('···');
  // }

  // WiFi连接成功后将通过串口监视器输出连接成功信息
  // if (debug)
  // {
  //   Serial.println('\n');
  //   Serial.print("Connected to ");
  //   Serial.println(WiFi.SSID()); // 通过串口监视器输出连接的WiFi名称
  //   Serial.print("IP address:\t");
  //   Serial.println(WiFi.localIP()); // 通过串口监视器输出ESP8266-NodeMCU的IP
  // }

  if (SPIFFS.begin() && debug)
  { // 启动闪存文件系统
    Serial.println("SPIFFS Started.");
  }
  else if (debug)
  {
    Serial.println("SPIFFS Failed to Start.");
  }

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  if (WiFi.softAP(AP_NAME))
  {
    Serial.println("ESP8266 SoftAP is right");
  }

  // 初始化网络服务器

  esp8266_server.on("/Page-Init-p", handleInit_p);
  esp8266_server.on("/Page-Init-b", handleInit_b);
  esp8266_server.on("/LED-Color", handleColor);
  esp8266_server.on("/LED-Brightness", handleBrightness);
  esp8266_server.on("/LED-Pattern", handlePattern);
  esp8266_server.on("/TURN-OFF_ON", handleTurn);
  
  ////设置dns劫持 来实现强制门户
  esp8266_server.on("/", HTTP_GET, handleDNS); // 设置主页回调函数
  esp8266_server.on("/", HTTP_POST, handleDNS);//设置Post请求回调函数
  esp8266_server.onNotFound(handleUserRequest); // 处理其它网络请求

  // 启动网站服务
  esp8266_server.begin();
  Serial.println("HTTP server started");

  // 初始化DNS服务器
  if (dnsServer.start(DNS_PORT, "*", apIP))
  { // 判断将所有地址映射到esp8266的ip上是否成功
    Serial.println("start dnsserver success.");
  }
  else
    Serial.println("start dnsserver failed.");

  // 读取闪存文件系统中的模式和亮度存储状态
  File ftsp = SPIFFS.open(filetostorepattern, "r");
  pattern = ftsp.read();
  ftsp.close();

  File ftsb = SPIFFS.open(filetostorebrightness, "r");
  brightness = (int)ftsb.read();
  ftsb.close();

  File ftsi = SPIFFS.open(filetostoreindex, "r");
  INDEX = (bool)ftsi.read();
  ftsb.close();

  if (debug)
  {
    Serial.print("The last pattern is ");
    Serial.println(pattern);
    Serial.print("The last brightness is ");
    Serial.println(brightness);
    Serial.print("The last INDEX is ");
    Serial.println(INDEX);

  }

  // 按键检测部分
  pinMode(BUTTON, INPUT_PULLUP);
  pinMode(BUTTON_INDEX, INPUT_PULLUP);

}

void loop()
{
  esp8266_server.handleClient(); // 处理网络请求
  dnsServer.processNextRequest();

if(TURN){
  // 模式切换部分
  switch (pattern)
  {

  case 0:
    flow_rainbow(10);
    break;

  case 1:
    breath_lamp(brightness, 3, RED, GREEN, BLUE);
    break;

  case 2:
    colorful_change();
    break;

  case 3:
    party_leap();
    break;

  default:
    break;
  }
}
else{
  FastLED.clear();
  FastLED.show();
}



  // 按键检测部分
  EVERY_N_MILLISECONDS(400)
  {
    button = digitalRead(BUTTON);
    button_index = digitalRead(BUTTON_INDEX);
    Button_Control();
  }
  if (pattern >= 4)
    pattern = 0;


}

void breath_lamp(uint8_t max_brightness, uint8_t pace, uint8_t RED, uint8_t GREEN, uint8_t BLUE) // 每pace 秒呼吸一次60  pace=60/x
{
  fill_solid(leds, NUM_LEDS, CRGB(RED, GREEN, BLUE));
  FastLED.setBrightness(beatsin8(60 / pace, 10, max_brightness));
  FastLED.show();
}

void colorful_change() // 所有灯是一个颜色然后变化
{
  EVERY_N_MILLISECONDS(50)
  {
    fill_solid(leds, NUM_LEDS, CHSV(++i, 240, 255));
    FastLED.setBrightness(brightness);
    FastLED.show();
  }
}

void party_leap()
{
  int pos = random8(NUM_LEDS);
  EVERY_N_MILLISECONDS(100)
  {
    if (random8() < 80)
    {
      leds[pos] = ColorFromPalette(PartyColors_p, random8(255), 128, LINEARBLEND);
    }
  }
  EVERY_N_MILLISECONDS(20)
  {
    fadeToBlackBy(leds, NUM_LEDS, 10);
  }
  FastLED.setBrightness(brightness);
  FastLED.show();
  delay(50);
}

void flow_rainbow(uint8_t time)
{
  EVERY_N_MILLISECONDS(time)
  {
    if (i < 256)
      i++;
    if (i >= 256)
      i = 0;
    fill_rainbow(leds, NUM_LEDS, i, 35);
    FastLED.setBrightness(brightness);
    FastLED.show();
  }
}

// Web dispose

void handleInit_p()
{
  esp8266_server.send(200, "text/plain", (String)pattern); // 发送模拟输入引脚到客户端ajax请求
}
void handleInit_b()
{
  esp8266_server.send(200, "text/plain", (String)brightness); // 发送模拟输入引脚到客户端ajax请求
}


void handleColor()
{
  // 从浏览器发送的信息中获取控制数值（字符串格式）
  String R = esp8266_server.arg("RED");
  String G = esp8266_server.arg("GREEN");
  String B = esp8266_server.arg("BLUE");

  // 将接受到的String类型数据转为uint8_t类型
  RED = R.toInt();
  GREEN = G.toInt();
  BLUE = B.toInt();

  // 将用户输入的信息通过串口监视器显示出来
  if (debug)
  {
    Serial.print("R = ");
    Serial.println(R);
    Serial.print("  ");
    Serial.println(RED);

    Serial.print("G = ");
    Serial.println(G);
    Serial.print("  ");
    Serial.println(GREEN);

    Serial.print("B = ");
    Serial.println(B);
    Serial.print("  ");
    Serial.println(BLUE);
  }

  // return stastue code 200 to Ajax
  esp8266_server.send(200, "text/plain"); // 向客户端发送200响应信息
}

void handleBrightness()
{
  String brt = esp8266_server.arg("brightness");
  // 将接受到的String类型数据转为uint8_t类型
  brightness = brt.toInt();
  File ftsb = SPIFFS.open(filetostorebrightness, "w");
  ftsb.println(brt); // 向file-to-store-brightness写入字符串信息
  ftsb.close();             // 完成文件写入后关闭文件
  Serial.print("brightness: ");
  Serial.println(brightness);
    Serial.print("写入brightness：");
  Serial.println(brightness);
}

void handlePattern() // 处理按钮按下请求
{
  String pat = esp8266_server.arg("pattern");
  // 将接受到的String类型数据转为uint8_t类型
  pattern = pat.toInt();
  esp8266_server.send(200, "text/plain");
  // 存储状态
  File ftsp = SPIFFS.open(filetostorepattern, "w");
  ftsp.println(pattern); // 向file-to-store-pattern写入字符串信息
  ftsp.close();          // 完成文件写入后关闭文件
  Serial.print("写入pattern ：");
  Serial.println(pattern);
}

void handleTurn(){
  String tur=esp8266_server.arg("turn");
  TURN=tur.toInt();

  Serial.print("TURN = ");
  Serial.println(TURN);
}

void handleIndex(){
  File file = SPIFFS.open("index.html", "r");       // 则尝试打开该文件
    esp8266_server.streamFile(file, "text/html"); // 并且将该文件返回给浏览器
    file.close();                                 // 并且关闭文件

}


// 处理用户浏览器的HTTP访问

void handleDNS()
{
   File file = SPIFFS.open("LED.html", "r");       // 则尝试打开该文件
    esp8266_server.streamFile(file, "text/html"); // 并且将该文件返回给浏览器
    file.close();                                 // 并且关闭文件

}
void handleUserRequest()
{

  // 获取用户请求资源(Request Resource）
  String reqResource = esp8266_server.uri();
  Serial.print("reqResource: ");
  Serial.println(reqResource);

  // 通过handleFileRead函数处处理用户请求资源
  bool fileReadOK = handleFileRead(reqResource);

  // 如果在SPIFFS无法找到用户访问的资源，则打开index
  if (!fileReadOK)
  {
    //esp8266_server.send(404, "text/plain", "404 Not Found");//回复404 (Not Found)
    reqResource  = "/wifi.html";
    handleFileRead(reqResource);
  }
}

bool handleFileRead(String resource)
{ // 处理浏览器HTTP访问

  if (resource.endsWith("/"))
  {                           // 如果访问地址以"/"为结尾
    resource = "/wifi.html"; // 则将访问地址修改为/index.html便于SPIFFS访问
  }

  String contentType = getContentType(resource); // 获取文件类型

  if (SPIFFS.exists(resource))
  {                                               // 如果访问的文件可以在SPIFFS中找到
    File file = SPIFFS.open(resource, "r");       // 则尝试打开该文件
    esp8266_server.streamFile(file, contentType); // 并且将该文件返回给浏览器
    file.close();                                 // 并且关闭文件
    return true;                                  // 返回true
  }
  return false; // 如果文件未找到，则返回false
}

// 获取文件类型
String getContentType(String filename)
{
  if (filename.endsWith(".htm"))
    return "text/html";
  else if (filename.endsWith(".html"))
    return "text/html";
  else if (filename.endsWith(".css"))
    return "text/css";
  else if (filename.endsWith(".js"))
    return "application/javascript";
  else if (filename.endsWith(".png"))
    return "image/png";
  else if (filename.endsWith(".gif"))
    return "image/gif";
  else if (filename.endsWith(".jpg"))
    return "image/jpeg";
  else if (filename.endsWith(".ico"))
    return "image/x-icon";
  else if (filename.endsWith(".xml"))
    return "text/xml";
  else if (filename.endsWith(".pdf"))
    return "application/x-pdf";
  else if (filename.endsWith(".zip"))
    return "application/x-zip";
  else if (filename.endsWith(".gz"))
    return "application/x-gzip";
  return "text/plain";
}

// Button detection
void Button_Control()
{
  button = digitalRead(BUTTON);
  if (button == 0)
  {
    delay(10);
    button = digitalRead(BUTTON);
    if (button == 0)
    {
      count = 0;
      button = digitalRead(BUTTON);
      while (button == 0) // long press to turn off
      {
        delay(20);
        ++count;
        if (count >= 75)
        {
          off_set();
          count = 0;
        }
        button = digitalRead(BUTTON);
      }
      pattern++; // click to switch pattern
      File ftsp = SPIFFS.open(filetostorepattern, "w");
      ftsp.println(pattern); // 向file-to-store-pattern写入字符串信息
      ftsp.close();          // 完成文件写入后关闭文件
    }
  }


  button_index=digitalRead(BUTTON_INDEX);
    if (button_index == 0)
  {
    delay(10);
     button_index=digitalRead(BUTTON_INDEX);
    if (button_index == 0)
    {
      INDEX=1;
      File ftsi = SPIFFS.open(filetostoreindex, "w");
  ftsi.println(INDEX); // 向file-to-store-pattern写入字符串信息
  ftsi.close();          // 完成文件写入后关闭文件
      Serial.print("INDEX:");
      Serial.println(INDEX);
      }
      }

}

void off_set()
{ // 休眠函数
  // test
  Serial.println("test to off_set");
  delay(1000);
}
